/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.ui.cd;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;

import org.apache.log4j.Logger;

import who.tmap.bo.ThematicMap;
import who.tmap.bo.cd.CDColorPattern;
import who.tmap.bo.cd.CDTypes;
import who.tmap.bo.cd.CartographicDisplay;
import who.tmap.bo.cd.ColorPatternClassification;
import who.tmap.bo.cd.impl.CartographicDisplayFactory;
import who.tmap.common.TMapException;
import who.tmap.ui.util.MiscUIHelper;

/**
 * Dedicated to the color/pattern (choroplethic) cartographic display
 * @author stl
 */
public class JPanelCDColorPattern extends JPanel 
								  implements PanelCD {//, SimpleObserved {

    private static Logger logger = Logger.getLogger(JPanelCDColorPattern.class);
    
	public static final int DEFAULT_NB_RANGES =4;
	public static final int DEFAULT_MISSING_DATA_RANGE =1;
	
	//private SimpleObservedImpl observedImpl =new SimpleObservedImpl();
	// package visibility for helper access only
	RangeTableModel dataModel =null;
	private ThematicMap thematicMap =null;  
	private JPanel thisPanel =this;
	
	private boolean dirty =false;
	private boolean rangesUpdated =false;
	// package visibility for helper access only
	List<String> rangeForValues;
	
	private JPanelCDHelper jPanelCDHelper =new JPanelCDHelper();  

	private JComboBox jComboBoxDataColumn = null;
	private JComboBox jComboBoxAttrClassification = null;
	private JLabel jLabelNbRanges = null;
	private JTextField jTextFieldNbRanges = null;
	private JTextField jTextFieldMissingDataRange = null;
	private JTable jTableRange = null;
	private JScrollPane jScrollPaneRange = null;
	private JTabbedPane jTabbedPane = null;
	private JPanel jPanelData = null;
	private JPanel jPanelRange = null;
	private JPanel jPanelRangeInfo = null;
	private JComboBox jComboBoxJoinIdColumn = null;

	private JPanel jPanelDataInfo = null;
	// package visibility for helper access only
	TableCellEditor[] colorEditors;
	TableCellRenderer[] colorRenderers;

	private JPanel jPanelRangeInfoTop = null;
	
	private JPanelCDColorPatternHelper helper;
	
	/**
	 * This is the default constructor
	 */
	public JPanelCDColorPattern() {
		super();
		initialize();
	}
	
	/**
	 * This method initializes this
	 * 
	 * @return void
	 */
	private void initialize() {
		setLayout( new BorderLayout() );
		add(getJTabbedPane(), BorderLayout.CENTER);
		setSize(300, 200);
		
		helper =new JPanelCDColorPatternHelper( this );
	}
	
	/**
	 * This method initializes jComboBoxData
	 * 
	 * @return javax.swing.JComboBox
	 */
	public JComboBox getJComboBoxDataColumn() {
		if(jComboBoxDataColumn == null) {
			jComboBoxDataColumn = new JComboBox();
			jComboBoxDataColumn.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e) {
					setDirty(true);
				}
			});
		}
		return jComboBoxDataColumn;
	}
	
	/**
	 * This method initializes jComboBoxAttrClassification
	 * 
	 * @return javax.swing.JComboBox
	 */
	public JComboBox getJComboBoxAttrClassification() {
		if(jComboBoxAttrClassification == null) {
			jComboBoxAttrClassification = new JComboBox( ColorPatternClassification.names );

			jComboBoxAttrClassification.addActionListener( new ClassificationAction( this ) );
			
		}
		return jComboBoxAttrClassification;
	}
	
	/**
	 * This method initializes Ranges
	 * 
	 * @return javax.swing.JLabel
	 */
	public JLabel getJLabelNbRanges() {
		if(jLabelNbRanges == null) {
			jLabelNbRanges = new JLabel();
			jLabelNbRanges.setText("# ranges");
		}
		return jLabelNbRanges;
	}
	
	/**
	 * This method initializes jTextFieldNbRanges
	 * 
	 * @return javax.swing.JTextField
	 */
	public JTextField getJTextFieldNbRanges() {
		if(jTextFieldNbRanges == null) {
			jTextFieldNbRanges = new JTextField();
			jTextFieldNbRanges.setText( String.valueOf( DEFAULT_NB_RANGES ) );
			
			jTextFieldNbRanges.addKeyListener(new KeyAdapter() {
				public void keyTyped(KeyEvent e) {
					setDirty( true );
					rangesUpdated =true;
				}
			});
		}
		return jTextFieldNbRanges;
	}
		
	public void updateRanges() {
		helper.updateRanges();
	}
	
	/**
	 * This method initializes jTextFieldMissingDataRange
	 * 
	 * @return javax.swing.JTextField
	 */
	public JTextField getJTextFieldMissingDataRange() {
		if(jTextFieldMissingDataRange == null) {
			jTextFieldMissingDataRange = new JTextField();
			jTextFieldMissingDataRange.setText( String.valueOf( DEFAULT_MISSING_DATA_RANGE ) );
			jTextFieldMissingDataRange.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					int missingRange =getMissingDataRange();
				}
			});
			
			jTextFieldMissingDataRange.addKeyListener(new java.awt.event.KeyAdapter() {
				public void keyTyped(java.awt.event.KeyEvent e) {
					setDirty( true );
				}
			});
		}
		return jTextFieldMissingDataRange;
	}
	
	private int getMissingDataRange() {
		int  missingDataRange =0;
		try {
			missingDataRange =Integer.parseInt( getJTextFieldMissingDataRange().getText() );
		} catch( Exception e ) {
			missingDataRange =DEFAULT_MISSING_DATA_RANGE;
			getJTextFieldMissingDataRange().setText( String.valueOf( missingDataRange ) );
		}
		
		return missingDataRange;
	}
	
	/**
	 * This method initializes jTableRange
	 * 
	 * @return JTable
	 */
	public JTable getJTableRange() {
		if(jTableRange == null) {
			dataModel = new RangeTableModel();	

			jTableRange =new JTable( dataModel ) {
				
				/**
				 *  Select the text when the cell starts editing
				 *  a) text will be replaced when you start typing in a cell
				 *  b) text will be selected when you use F2 to start editing
				 *  c) caret is placed at end of text when double clicking to start editing
				 */  
				public Component prepareEditor( TableCellEditor editor, int row, int column ) {
					Component c = super.prepareEditor(editor, row, column);
	 
					if (c instanceof JTextComponent) {
						((JTextField)c).selectAll();
					} 
					
					return c;
				}				
				
	            /**
	             * Determine editor to be used by row
	             */  
	            public TableCellEditor getCellEditor(int row, int column) {
	                if (column == RangeTableModel.COLOR_COL ) {
	                    return colorEditors[ row ];
	                } else {
	                    return super.getCellEditor(row, column);
	                }
	            }
	            
	            public TableCellRenderer getCellRenderer(int row, int column) {
	                if (column == RangeTableModel.COLOR_COL ) {
	                    return colorRenderers[ row ];
	                } else {
	                    return super.getCellRenderer(row, column);
	                }	            	
	            }
				
				/**
				 * Color every other row
				 */
				public Component prepareRenderer( TableCellRenderer renderer
				          						  , int rowIndex, int vColIndex ) {
					  Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
					  if (rowIndex % 2 == 0 ) {
						  c.setBackground(MiscUIHelper.TABLE_CELL_BG_COLOR);
					  } else {
						  // If not shaded, match the table's background
						  c.setBackground(getBackground());
						  if ( c.getBackground().equals( c.getForeground() ) ) {
							  c.setForeground( Color.black );
						  }
					  }
					  return c;
				}
			
	        };
			
			TableColumn patternCol =jTableRange.getColumnModel().getColumn( RangeTableModel.FILL_PATTERN_COL );
			patternCol.setCellRenderer( new TableComboBoxRendererPattern() );			
			JComboBoxPattern patternCb =new JComboBoxPattern();			
			patternCol.setCellEditor( new DefaultCellEditor( patternCb ) );
			
			// Causes JComboBox inside JTable to fail with Java 6 !
			//jTableRange.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

		}
		return jTableRange;
	}
	
	/**
	 * This method initializes jScrollPaneRange
	 * 
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPaneRange() {
		if(jScrollPaneRange == null) {
			jScrollPaneRange = new JScrollPane();
			jScrollPaneRange.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
			jScrollPaneRange.setViewportView(getJTableRange());
		}
		return jScrollPaneRange;
	}
	
	/**
	 * This method initializes jTabbedPane
	 * 
	 * @return javax.swing.JTabbedPane
	 */
	private JTabbedPane getJTabbedPane() {
		if(jTabbedPane == null) {
			jTabbedPane = new JTabbedPane();
			jTabbedPane.addTab("Data", null, getJPanelData(), null);
			jTabbedPane.addTab("Range", null, getJPanelRange(), null);
		}
		return jTabbedPane;
	}
	
	/**
	 * This method initializes jPanelData
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelData() {
		if(jPanelData == null) {
			jPanelData = new JPanel();
			jPanelData.setLayout( new BorderLayout() );
			jPanelData.add( getJPanelDataInfo(), BorderLayout.NORTH );
			jPanelData.add( Box.createVerticalGlue(), BorderLayout.CENTER );			
		}
		return jPanelData;
	}
	
	/**
	 * This method initializes jPanelRange
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelRange() {
		if(jPanelRange == null) {
			jPanelRange = new JPanel();
			jPanelRange.setLayout(new BorderLayout());
			jPanelRange.add(getJScrollPaneRange(), BorderLayout.CENTER);
			jPanelRange.add(getJPanelRangeInfoTop(), BorderLayout.NORTH);
		}
		return jPanelRange;
	}
	
	/**
	 * This method initializes jPanel
	 * 
	 * @return javax.swing.JPanel
	 */
	public JPanel getJPanelRangeInfo() {
		if(jPanelRangeInfo == null) {
			jPanelRangeInfo = new JPanel();
			java.awt.GridLayout layGridLayout3 = new java.awt.GridLayout(2,2,5,5);
			jPanelRangeInfo.setLayout(layGridLayout3);
			jPanelRangeInfo.add(getJLabelNbRanges(), null);
			jPanelRangeInfo.add(getJTextFieldNbRanges(), null);
			jPanelRangeInfo.add( new JLabel( "Missing data range #"), null);
			jPanelRangeInfo.add(getJTextFieldMissingDataRange(), null);
		}
		return jPanelRangeInfo;
	}
	
	public ThematicMap getThematicMap() {
		return thematicMap;
	}
	
	public void setThematicMap(ThematicMap thematicMap) {
		this.thematicMap = thematicMap;
	}
	
	public void refreshAttrColumnNames() {
		jPanelCDHelper.populateJComboBox( thematicMap, getJComboBoxJoinIdColumn() );
		jPanelCDHelper.populateJComboBox( thematicMap, getJComboBoxDataColumn() );
		
		jPanelCDHelper.selectDefaultJoinIdAndDataColumns( getJComboBoxJoinIdColumn(), getJComboBoxDataColumn() );
	}
	
	public void refreshData() {
		helper.refreshData();
	}
	
	public CartographicDisplay getCartographicDisplay() throws TMapException {
		CDColorPattern cd =(CDColorPattern)CartographicDisplayFactory.getInstance().get( CDTypes.COLOR_PATTERN );
		
		cd.setRanges( dataModel.getRanges() );	
		
		cd.setJoinIdColumnName( (String)getJComboBoxJoinIdColumn().getSelectedItem() );
		cd.setDataColumnName( (String)getJComboBoxDataColumn().getSelectedItem() );
		cd.setPolygonAssociatedData( null );
		
		cd.setClassification( getJComboBoxAttrClassification().getSelectedIndex() );		
		cd.setMissingDataRangeIdx( getMissingDataRange() );
		
		if ( cd.getClassification() == ColorPatternClassification.NON_NUMERIC && isDirty() ) {
			helper.processNonNumeric();
			updateRanges();
			refreshRanges();
		}
		
		return cd;
	}
	
	public void processNonNumeric() throws TMapException {
		helper.processNonNumeric();
	}
	
	/**
	 * This method initializes jComboBoxJoinIdColumn	
	 * 	
	 * @return javax.swing.JComboBox	
	 */
	public JComboBox getJComboBoxJoinIdColumn() {
		if (jComboBoxJoinIdColumn == null) {
			jComboBoxJoinIdColumn = new JComboBox();
			jComboBoxJoinIdColumn.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					setDirty( true );
				}
			});
		}
		return jComboBoxJoinIdColumn;
	}
	
	private int getNbRanges() {
		int nbRanges =0;
		try {
			nbRanges =Integer.parseInt( getJTextFieldNbRanges().getText() );
		} catch( Exception e ) {
			
		}
		
		return nbRanges;
	}

	/**
	 * This method initializes jPanelDataInfo	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getJPanelDataInfo() {
		if (jPanelDataInfo == null) {
			
			jPanelDataInfo = new JPanel();
			GridLayout layGridLayout2 = new GridLayout(3,2,5,5);
			jPanelDataInfo.setLayout(layGridLayout2);	
			jPanelDataInfo.add( new JLabel( "Join ID column" ), null);			
			jPanelDataInfo.add(getJComboBoxJoinIdColumn(), null);
			
			jPanelDataInfo.add( new JLabel( "Data column" ), null);
			jPanelDataInfo.add(getJComboBoxDataColumn(), null);
			
			jPanelDataInfo.add( new JLabel( "Classification" ), null);
			jPanelDataInfo.add(getJComboBoxAttrClassification(), null);
			jPanelDataInfo.setBorder( BorderFactory.createEmptyBorder (5, 5, 5, 5) );

		}
		return jPanelDataInfo;
	}
	
	/**
	 * This method initializes jPanelRangeInfoTop	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getJPanelRangeInfoTop() {
		if (jPanelRangeInfoTop == null) {
			jPanelRangeInfoTop = new JPanel();
			jPanelRangeInfoTop.add(getJPanelRangeInfo());
		}
		
		return jPanelRangeInfoTop;
	}
	
	public void refreshRanges() {
		dataModel.fireTableDataChanged();
		getJTableRange().revalidate();
		//logger.debug( "refreshRanges" );
	}

	public boolean isDirty() {
		return dirty || dataModel.isDirty();
	}

	public void setDirty(boolean dirty) {
		this.dirty = dirty;
		dataModel.setDirty( dirty );
	}
	
	public boolean isRangesUpdated() {
		return rangesUpdated;
	}
	
	public void setRangesUpdated( boolean rangesUpdated ) {
		this.rangesUpdated =rangesUpdated;
	}

	/*public void notifyObservers(Object msg) {
		observedImpl.notifyObservers( msg );
	}

	public void registerObserver(SimpleObserver observer) {
		observedImpl.registerObserver( observer );
	}

	public void unregisterObserver(SimpleObserver observer) {
		observedImpl.unregisterObserver( observer );
	}*/
	
	public String getDataColumnName() {
		return (String)getJComboBoxDataColumn().getSelectedItem();
	}
	
	public String getJoinIdColumnName() {
		return (String)getJComboBoxJoinIdColumn().getSelectedItem();
	}

	public void setDataColumnName(String dataColumnName) {
		getJComboBoxDataColumn().setSelectedItem( dataColumnName );
	}

	public void setJoinIdColumnName(String joinIdColumnName) {
		getJComboBoxJoinIdColumn().setSelectedItem( joinIdColumnName );
	}
		
}
